#ifndef XGE_XMEM_UTILITY_H_
#define XGE_XMEM_UTILITY_H_
#include "xge_common_config.h"
#include "xallocator.h"
#include "xsys_log.h"
#include "xassert.h"


namespace xge{

  using xge_internal::XMalloc;
  using xge_internal::XFree;

  class MemoryPool : public Allocator {
  public:
    inline MemoryPool(
      size_t base_reserve_size,
      size_t alignment_size,
      size_t object_size
      ) ;
    inline ~MemoryPool();
  public:
    // This function may fail : when the reserved memory is not enough
    // You Should Call The Grow explicitly 
    void* Buy();

    // This function will put the memory back into the memory pool 
    void  Sell( void* ptr );
    // Grow the internal pool :
    // You should call this function explicitly 
    // when you do the operation:
    // T* ptr = mem.Buy() ;
    void  Grow( size_t ratio=1 );
    // Free all the memory block in the pool
    // You should notice that ALL the block will be
    // free , therefore , any allocated memory block
    // will be invalid !!!
    // If the force value is false . The pool will 
    // check if the size == 0 , if so the pool will
    // do the free job and return true 
    // otherwise , if won't do the clear
    // if the force is true 
    // it will do the clear anyway 
    bool Clear( bool force = false );

  public:

    bool   empty()        const {
      return next_ == NULL;
    }
    size_t alloc_size()   const {
      return alloc_size_;
    }
    size_t residual_size() const {
      return residual_size_;
    }
    size_t base_reserve_size() const{
      return base_reserve_size_;
    }

    void set_base_reserve_size( size_t size ) {
      base_reserve_size_ = size;
    }

    size_t alignment_size() const {
      return alignment_size_;
    }

    size_t object_size() const {
      return object_size_;
    }

  private:
     size_t Padding( size_t original , size_t pad ) {
      return static_cast<size_t> ( (original + pad-1)& ~(pad-1) );
    }
  private:
    // Free list 
    struct FreeList {
      // This pointer will point to the start of the next block of memory
      FreeList* next_addr;
    };
    // Linked list for recording how many block of memory has been allocated
    struct LinkedList {
      size_t block_size;
      LinkedList* next_block;
    };
    // The next available address
    FreeList* next_;
    // Size of the allocated size
    size_t alloc_size_;
    // Start place
    LinkedList* block_ptr_  ;
    // Residual size
    size_t residual_size_;
    // reserve size
    size_t base_reserve_size_;
    // alignment size
    size_t alignment_size_;
    // object size
    size_t object_size_;
    // not allow to copy and assign
    DISALLOW_COPY_AND_ASSIGN( MemoryPool );

  };

  inline MemoryPool::MemoryPool( size_t base_reserve_size , size_t alignment_size, size_t object_size ):
    next_(NULL),
    block_ptr_(NULL),
    alloc_size_(0),
    residual_size_(0),
    base_reserve_size_(base_reserve_size),
    object_size_(object_size),
    alignment_size_(alignment_size){
      Grow();
  }


  inline MemoryPool::~MemoryPool() {
    Clear();
  }


} // namespace xge
#endif// XGE_XMEM_UTILITY_H_